package model;

import helper.Utils;

import java.util.ArrayList;

public class Register {
	private boolean[] value;
	private MinCommandSet minCommandSet;
	private int width;
	private int opcodeWidth;

	public Register(MinCommandSet minCommandSet, int width, int opcodeWidth) {
		this.width = width;
		this.opcodeWidth = opcodeWidth;
		this.minCommandSet = minCommandSet;
	}

	public void setOpcodeWidth(int opcodeWidth) {
		this.opcodeWidth = opcodeWidth;
	}

	public void setValue(int value) {
		this.value = Utils.tailorBooleanArray(Utils.int2booleanArray(value), width);
	}

	public int getValue() {
		return Utils.booleanArray2int(this.value);
	}

	public void setMinCommandSet(MinCommandSet minCommandSet) {
		this.minCommandSet = minCommandSet;
	}

	public MinCommandSet getMinCommandSet() {
		return minCommandSet;
	}

	public int getWidth() {
		return width;
	}

	public int getOpcodeWidth() {
		return opcodeWidth;
	}

	private boolean[] getPartOfValue(int start, int end) {
		boolean[] result = new boolean[end - start];
		for (int i = start; i < end; i++) {
			result[i - start] = value[i];
		}
		return result;
	}

	/**
	 * Returns the command according to its opcode and the parameters. Therefore
	 * the width of one parameter is computed (width - opcodeWidth) / paramCount
	 * 
	 * This means that there could be an unused bit, for example for an even
	 * width with an uneven opcode width and 2 parameters
	 */
	public CodeLine getCommand() {
		boolean[] bitcode = new boolean[opcodeWidth];
		for (int i = 0; i < opcodeWidth; i++) {
			bitcode[i] = this.value[i];
		}
		int code = Utils.booleanArray2int(bitcode);
		Command cmd = minCommandSet.getCommandForOpcode(code);
		if (cmd == null) {
			return new Constant(code);
		}
		ArrayList<CommandParameter> params = new ArrayList<CommandParameter>();
		int paramLength;
		if (cmd.getParameterCount() > 1) {
			paramLength = (width - opcodeWidth) / cmd.getParameterCount();
		} else {
			paramLength = (width - opcodeWidth);
		}
		for (int i = 0; i < cmd.getParameterCount(); i++) {
			boolean[] param = getPartOfValue(i * paramLength + opcodeWidth,
					(i + 1) * paramLength + opcodeWidth - 1);
			Reference cmdParam = new Reference(Utils.booleanArray2int(param));
			params.add(cmdParam);
		}
		cmd.setCommandParameter(params);
		return cmd;
	}

}
